﻿using System;
using System.Reflection;
using System.Collections;
using OpenExpressApp.ORM;
using Csla;
using lite;
using Csla.Validation;
using Csla.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Data;
using System.Data.OleDb;
using System.Text;
using System.Collections.Generic;


namespace ZX.DBModule
{
    /// <summary>
    /// 说明：实体基类
    /// 
    /// </summary>
    [Serializable]
    public class BaseEntity : BusinessBase<BaseEntity>
    {
        /// <summary>
        /// 數據複製，把自身複製一份。
        /// </summary>
        /// <returns>返回被複製的對象</returns>
        public virtual BaseEntity Clone()
        {
            Type theType = this.GetType();
            BaseEntity Result = (BaseEntity)Activator.CreateInstance(theType);
            PropertyInfo[] Mypropertyinfos =  this.GetType().GetProperties();
            foreach(PropertyInfo proInfo in Mypropertyinfos)
            {   
                PropertyInfo prop = theType.GetProperty(proInfo.Name);
                if (prop == null)
                    continue;
                if (prop.CanWrite && prop.CanRead)
                {
                    object value1 = prop.GetValue(this, null);
                    if (value1 != null)
                    {
                        if (prop.PropertyType.GetInterface(typeof(ICollection).ToString(), true) == null)
                        {
                            object temp = this;
                            //member.StorageAccessor.SetBoxedValue(ref temp, value1);
                            prop.SetValue(Result, value1, null);
                        }
                    }
                }
            }
            return Result;
        }

        public void SetConn(BaseEntity entity)
        {

        }

        public void SetConn()
        {
        }

        /// <summary>
        /// 管理子类
        /// </summary>
        public Dictionary<string, IList<BaseEntity>> _SubList;
        public Dictionary<string,IList<BaseEntity>> SubList
        {
            get {return _SubList;}
            set { _SubList = value;}
        }
        /// <summary>
        /// 获取子类列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IList<T> GetChilds<T>(string tablename,string FKey,Guid FKeyValue) where T:BaseEntity
        {
            DAL.DBExtend.DbSql db = new DAL.DBExtend.DbSql();
            string strSql = "select * from " + tablename + " where " + FKey + "='" + FKeyValue + "'";
            DataTable dt = db.ExecuteQuery(strSql);
            return DatatableToObject<T>(dt);
        }

        public IList<T> GetChilds<T>(string tablename, string condition) where T : BaseEntity
        {
            DAL.DBExtend.DbSql db = new DAL.DBExtend.DbSql();
            string strSql = "select * from " + tablename + " where " + condition;
            DataTable dt = db.ExecuteQuery(strSql);
            return DatatableToObject<T>(dt);
        }

        public static IList<T> GetList<T>(string tablename, string condition) where T : BaseEntity
        {
            DAL.DBExtend.DbSql db = new DAL.DBExtend.DbSql();
            string strSql = "select * from " + tablename + " where " + condition;
            DataTable dt = db.ExecuteQuery(strSql);
            return DatatableToObject<T>(dt);
        }

        /// <summary>
        /// 获取外键信息
        /// </summary>
        /// <param name="Table">表名</param>
        /// <returns></returns>
        public IList<SysTableFKey> GetFKey(string Table)
        {
            string strSql = string.Format(@"select t1.name as FieldName, t2.rtableName as FKTableName,
            t2.name as FKFieldName from (select col.name, f.constid as temp  from syscolumns col,sysforeignkeys f  where f.fkeyid=col.id  and f.fkey=col.colid  and f.constid in  
            ( select distinct(id)     from sysobjects    where OBJECT_NAME(parent_obj)='{0}'
                and xtype='F'   )  ) as t1 , (
            select OBJECT_NAME(f.rkeyid) as rtableName,col.name, f.constid as temp  from 
            syscolumns col,sysforeignkeys f  
            where f.rkeyid=col.id  and f.rkey=col.colid  
            and f.constid in  ( select distinct(id)    from sysobjects   
             where OBJECT_NAME(parent_obj)='{0}'    and xtype='F'  ) )
             as t2 where t1.temp=t2.temp", Table);
            DAL.DBExtend.DbSql db = new DAL.DBExtend.DbSql();
            DataTable dt = db.ExecuteQuery(strSql);
            return DatatableToObject<SysTableFKey>(dt);      
        }

        public IList<SysTableFKey> GetFKey()
        {
            return GetFKey(this.GetTableName());
        }



        //public IList<BaseEntity> GetMasterChilds(string tablename, string condition)
        //{
        //    DAL.DBExtend.DbSql db = new DAL.DBExtend.DbSql();
        //    string strSql = "select * from " + tablename + " where " + condition;
        //    DataTable dt = db.ExecuteQuery(strSql);
        //    //IList<BaseEntity> list = DatatableToObject(dt);
        //    IList<BaseEntity> _list = new List<BaseEntity>();
        //    //foreach (BaseEntity t in list)
        //    //{
        //    //    _list.Add(t as BaseEntity);
        //    //}
        //    //return _list;
        //}

        public IList<BaseEntity> GetMasterChilds<T>(string tablename, string condition) where T : BaseEntity
        {
            DAL.DBExtend.DbSql db = new DAL.DBExtend.DbSql();
            string strSql = "select * from " + tablename + " where " + condition;
            DataTable dt = db.ExecuteQuery(strSql);
            IList<T> list = DatatableToObject<T>(dt);
            IList<BaseEntity> _list = new List<BaseEntity>();
            foreach(T t in list)
            {
                _list.Add(t as BaseEntity);
            }
            return _list;
        }
        /// <summary>
        /// 通过查询结果，返回实体数组;
        /// </summary>
        /// <param name="dt">查询结果</param>
        /// <returns>实体对象</returns>
        public static IList<T> DatatableToObject<T>(DataTable dt) where T:BaseEntity
        {
            if (dt.Rows.Count == 0)
            {
                return null;
            }
            Type t = Activator.CreateInstance<T>().GetType();
            PropertyInfo[] Mypropertyinfos = t.GetProperties();
            IList<T> al = new List<T>();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                T _obj = System.Reflection.Assembly.GetAssembly(t).CreateInstance(t.ToString()) as T;
                foreach (PropertyInfo pi in Mypropertyinfos)
                {
                    if (pi.Name.IndexOf("iSun_") == 0)
                        continue;
                    try
                    {
                        _obj.SetPropertyValue(pi.Name, dt.Rows[i].ItemArray[dt.Columns[pi.Name].Ordinal].ToString());
                        //ZX.Common.Globals.SetPropertyValue(_obj, pi.Name, dt.Rows[i].ItemArray[dt.Columns[pi.Name].Ordinal].ToString());
                    }
                    catch (System.Exception e)
                    {
                        //log
                        //throw e;
                    }
                }
                al.Add(_obj);
            }
            return al;
        }

        public  void SetFieldValue(BaseEntity obj,string p,object v)
        {
            if (obj is DataTableBaseEntity)
            {
                ((DataTableBaseEntity)obj).SetValue(p, v);
            }
            else
            {
                obj.SetPropertyValue(p, v);
            }
        }
        /// <summary>
        /// 跟据类型名称,将DataTable转换成对象LIST
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="EntityName"></param>
        /// <returns></returns>
        public IList<BaseEntity> DatatableToObject(DataTable dt,string EntityName)
        {
            if (dt.Rows.Count == 0)
            {
                return null;
            }
            IList<SysLib> list = GetList<SysLib>("SysLib","LibType='e'");
            BaseEntity _entity = null;
            Type t = null;
            foreach(var en in list)
            {
                try
                {
                    t = Activator.CreateInstance(en.LibName + "." + EntityName, en.LibName).GetType();
                    _entity = System.Reflection.Assembly.GetAssembly(t).CreateInstance(t.ToString()) as BaseEntity;
                }
                catch { }
            }
  
            PropertyInfo[] Mypropertyinfos = t.GetProperties();
            IList<BaseEntity> al = new List<BaseEntity>();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                BaseEntity _obj = System.Reflection.Assembly.GetAssembly(t).CreateInstance(t.ToString()) as BaseEntity;
                foreach (PropertyInfo pi in Mypropertyinfos)
                {
                    if (pi.Name.IndexOf("iSun_") == 0)
                        continue;
                    try
                    {
                        _obj.SetPropertyValue(pi.Name, dt.Rows[i].ItemArray[dt.Columns[pi.Name].Ordinal].ToString());
                    }
                    catch (System.Exception e)
                    {
                   }
                }
                al.Add(_obj);
            }
            return al;
        }
        /// <summary>
        /// 数据置NULL
        /// </summary>
        /// <param name="AObject"></param>
        /// <param name="SetToNull"></param>
        public virtual void ClearData(BaseEntity AObject, bool SetToNull)
        {
            if (SetToNull)
            {
                AObject = null;
            }
        }

        /// <summary>
        /// 数据验证[]
        /// </summary>
        /// <returns>返回数据验证结果</returns>
        public virtual string CheckData()
        {
            return "";
        }


        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// 对象比较
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool Equals(BaseEntity obj)
        {
            if (!(obj is BaseEntity))
                return base.Equals(obj);

            if (obj.GetType() != this.GetType())
                return false;

            BaseEntity ASource = obj as BaseEntity;

            Type theType = this.GetType();

            object[] Attr = theType.GetCustomAttributes(typeof(TableAttribute), true);
            if (Attr.Length == 0)
                return false;
            PropertyInfo[] Mypropertyinfos = this.GetType().GetProperties();
            foreach (PropertyInfo proInfo in Mypropertyinfos)
            { 
                PropertyInfo prop = theType.GetProperty(proInfo.Name);

                Object Value1 = prop.GetValue(this, null);
                Object Value2 = prop.GetValue(ASource, null);
                if ((Value1 == null && Value2 != null) || (Value1 != null && Value2 == null))
                    return false;

                if (Value1 != null)
                {
                    if (!Value1.Equals(Value2))
                        return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 获取当前实体对应的表名
        /// </summary>
        /// <returns></returns>
        public string GetTableName()
        {
            var entity = (this as DataTableBaseEntity);
            if (entity != null)
            {
                return entity.TableName;
            }
            Type t = this.GetType();
            foreach (Attribute attr in t.GetCustomAttributes(true))
            {
                TableAttribute tableattribute = attr as TableAttribute;
                if (null != tableattribute)
                {
                    return tableattribute.TableName;
                }
            }
            return "";
        }


        /// <summary>
        /// 获取当前实体对应Guid？
        /// </summary>
        /// <returns></returns>
        public virtual string GetTableId()
        {
            var entity = (this as DataTableBaseEntity);
            if (entity != null)
            {
                return entity.TableKey;
            }
            Type t = this.GetType();
            foreach (Attribute attr in t.GetCustomAttributes(true))
            {
                TableAttribute tableattribute = attr as TableAttribute;
                if (null != tableattribute)
                {
                    return tableattribute.Guid;
                }
            }
            return "";
        }

        public virtual string GetTableIdValue()
        {
            var entity = (this as DataTableBaseEntity);
            if (entity != null)
            {
                if (((DataTableBaseEntity)entity).DRow[((DataTableBaseEntity)entity).TableKey] == null)
                {
                    return Guid.Empty.ToString();
                }
                return ((DataTableBaseEntity)entity).DRow[((DataTableBaseEntity)entity).TableKey].ToString();
            }
            Type t = this.GetType();
            string id = GetTableId();
            PropertyInfo prop = t.GetProperty(id);
            object value1 = prop.GetValue(this, null);

            return Convert.ToString(value1);
        }

        /// <summary>
        /// 获取当前实体对应的自增ID或整型ID
        /// </summary>
        /// <returns></returns>
        public string GetTableIdentity()
        {
            Type t = this.GetType();
            foreach (Attribute attr in t.GetCustomAttributes(true))
            {
                TableAttribute tableattribute = attr as TableAttribute;
                if (null != tableattribute)
                {
                    return tableattribute.Identity;
                }
            }
            return "";
        }
        
        

        /// <summary>
        /// 实休对象状态[新增，编辑，删除]
        /// </summary>
        public WorkState BaseEntityState
        {
            get;
            set;
        }

        /// <summary>
        /// 是否是Guid![单主键是否是Guid类]
        /// </summary>
        public bool IsGuid
        {
            get
            {
                return GetTableId() != "";
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public virtual bool iSun_Selected
        {
            get;
            set;
        }

        public bool iSun_IsNew
        {
            get;
            set;
        }

        /// <summary>
        /// 表示明细表对应的属性名称
        /// 如果有多个的时候用","分隔开
        /// 如:Detail1,Detail2;
        /// </summary>
        public virtual string DetailObject
        {
            get;
            set;
        }

        #region IComparable Members
        /// <summary>
        /// 数据比较
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public int CompareTo(object obj)
        {
            if (obj == null)
                return -1;
            if (this.Equals(obj))
                return 0;

            return 1;
        }
        #endregion


        #region Data Access 数据访问
        //由于DataPortal_create中没有对数据库的访问，所有标记了Runlocal特性，使得该方法只需在本地运行即可
        //如果代码中有访问数据库的方法，那么就不要用这个特性，使数据门户可以根据情况将此方法的运行选择在应用服务器还是本地
        [RunLocal()]
        protected virtual void DataPortal_Create()
        {
            //在此调用CheckRules对所有的属性进行验证规则的检查，这样检查只运行一次。
            ValidationRules.CheckRules();


        }

        /// <summary>
        /// 获取数据验证信息
        /// </summary>
        /// <returns></returns>
        public virtual string GetDataCheckMessage()
        {
            // 验证信息
            StringBuilder message = new StringBuilder("");
            if (this.BrokenRulesCollection.Count > 0)
            {
                foreach (var item in this.BrokenRulesCollection)
                {
                    message.Append(item.Description+"\n<br>");
                }
            }
            return message.ToString();
        }

        //可以看到此方法没有标记任何特性
        //此方法要访问数据库所以不能标记本地，由于她没有任何数据库更新操作所以也无需事务性的保护
        //此方法调用结束后会隐含的调用MarkOld（）方法
        protected  virtual void DataPortal_Fetch(object id)
        {
            base.DataPortal_Fetch(id);
        }

        //
        // 快速获取某特性属性
        //

        //这是一个事务安全的，此种方法标记事务是非常简单且有效的
        //数据门户会包裹这段代码，保证事务的完整运行成功，而且无需定义Ado的事务
        //[Transactional(TransactionalTypes.TransactionScope)]
        protected  virtual void DataPortal_Insert()
        {

            using (var ctx = GetConnectionManager())
            {
                IDb db = DbFactory.Instance.GetDb(ctx);
                db.Insert(this);
                // update child objects
                FieldManager.UpdateChildren(this);
            }
        }


        


        //[Transactional(TransactionalTypes.TransactionScope)]
        protected virtual void DataPortal_Update()
        {
            //如果是修改过的才有意义去更新此对象
            using (var ctx = GetConnectionManager())
            {
                IDb db = DbFactory.Instance.GetDb(ctx);
                db.Update(this);
                // update child objects
                FieldManager.UpdateChildren(this);
            }
        }

        /// <summary>
        /// 批量保存，含子类
        /// </summary>
        public virtual void DataPortal_BatchSave()
        {

        }

        public virtual BaseEntity GetEntityByID(BaseEntity entity,string ID)
        {
            using (var ctx = GetConnectionManager())
            {
                IDb db = DbFactory.Instance.GetDb(ctx);
                IQuery q = db.Query();
                q.Constrain(this.GetTableId()).Equal(ID);
                var data = db.Select(entity.GetType(), q);
                if (data.Count > 0)
                {
                    return data[0] as BaseEntity;
                }
                return null;
            }
        }

        //[Transactional(TransactionalTypes.TransactionScope)]
        protected override void DataPortal_DeleteSelf()
        {
            //依然是调用下面的方法删除的，只是他此时可以获得自己的Id
            DataPortal_Delete(this.GetTableId());
        }

        //[Transactional(TransactionalTypes.TransactionScope)]
        protected virtual void DataPortal_Delete()
        {
            using (var ctx = GetConnectionManager())
            {
                IDb db = DbFactory.Instance.GetDb(ctx);
                db.Delete(this);
            }
        }

        public virtual void Insert()
        {
            this.DataPortal_Insert();
        }

        public virtual void Update()
        {
            this.DataPortal_Update();
        }

        public virtual void Delete()
        {
            this.DataPortal_DeleteSelf();
        } 


        public const string ConnectionStringNames = "ConnString";
        public IDbConnection GetConnectionManager()
        {
            string DataType = ConfigurationManager.AppSettings["DataType"].ToString();
            if (DataType == null) { DataType = "SqlServer"; }
            IDbConnection mgr = null;
            switch (DataType)
            {
                case "SqlServer":
                    //(IDbConnection)ConnectionManager<SqlConnection>.GetManager(ConnectionStringNames).Connection;
                    //mgr = new SqlConnection("Data Source=192.168.6.200;Initial Catalog=zx_app_dev;User ID=dbop;Password=123;");
                    mgr = (IDbConnection)ConnectionManager<SqlConnection>.GetManager(ConnectionStringNames).Connection;
                    break;
                case "Oracle":
                    mgr = (IDbConnection)ConnectionManager<OleDbConnection>.GetManager(ConnectionStringNames).Connection;
                    break;
                default :
                    mgr = (IDbConnection)ConnectionManager<SqlConnection>.GetManager(ConnectionStringNames).Connection;
                    break;
            }
            return mgr;
        }
        #endregion


    }
}
